/*************************************************************
 * File: SerialNumberGeneratorUsingDatabase.java
 * Copyright (c) 2012
 * Author: Shaobin.Software@gmail.com Shaobin_Software@163.com 
 * Date: Jan 16, 2013
 * Description: 
 ************************************************************/
package snow.core.toolkit.generator;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;

import snow.core.toolkit.Constants;
import snow.core.toolkit.StringHelper;

/**
 * 使用数据库的方式生产序列号
 */
public class SerialNumberGeneratorUsingDatabase implements SerialNumberGenerator, InitializingBean {

	private Log log = LogFactory.getLog(getClass());

	private Integer radix; // 进制
	private Integer length; // 流水号长度
	private String insertSql; // 执行插入的SQL语句
	private String wordCharacters; // 生成字符串
	private JdbcTemplate jdbcTemplate; // 使用Spring的JDBC模板

	public void afterPropertiesSet() throws Exception {
		Assert.isTrue(StringUtils.isNotBlank(insertSql), "The property [insertSql] must not be blank!");
		Assert.isTrue(length != null && length.intValue() > 0, "The property [length] must be great than 0!");
	}

	/**
	 * @return
	 * @see snow.core.toolkit.generator.SerialNumberGenerator#generateSerialNumber()
	 */
	public String generateSerialNumber() {
		String serialNumber = "";
		final Long result = jdbcTemplate.execute(new ConnectionCallback<Long>() {
			/**
			 * @param connection
			 * @return
			 * @throws SQLException
			 * @throws DataAccessException
			 * @see org.springframework.jdbc.core.ConnectionCallback#doInConnection(java.sql.Connection)
			 */
			public Long doInConnection(Connection connection) throws SQLException, DataAccessException {
				final String sql = getInsertSql();
				log.debug("执行数据库插入的SQL语句：" + sql);
				Statement statement = connection.createStatement();
				statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
				ResultSet resultSet = statement.getGeneratedKeys();
				if (resultSet != null && resultSet.next()) {
					return resultSet.getLong(1);
				}
				return null;
			}
		});
		if (result != null && result.longValue() >= 0) {
			String wordCharacters = getWordCharacters();
			if (StringUtils.isBlank(wordCharacters)) {
				wordCharacters = Constants.WORD_CHARACTERS;
			}
			serialNumber = StringHelper.toString(wordCharacters, result.longValue(), getRadix().intValue());
			if (StringUtils.isNotBlank(serialNumber)) {
				serialNumber = serialNumber.trim();
				if (length != null && length > 0) {
					if (serialNumber.length() > length) {
						serialNumber = serialNumber.substring(0, length);
					} else {
						StringBuilder sb = new StringBuilder(serialNumber);
						for (int i = serialNumber.length(); i < length; i++) {
							sb.insert(0, wordCharacters.charAt(0));
						}
						serialNumber = sb.toString();
					}
				}
			}
		}
		return serialNumber;
	}

	public String getInsertSql() {
		return insertSql;
	}

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public Integer getLength() {
		return length;
	}

	public Integer getRadix() {
		return radix;
	}

	public String getWordCharacters() {
		return wordCharacters;
	}

	public void setInsertSql(String insertSql) {
		this.insertSql = insertSql;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public void setLength(Integer length) {
		this.length = length;
	}

	public void setRadix(Integer radix) {
		this.radix = radix;
	}

	public void setWordCharacters(String wordCharacters) {
		this.wordCharacters = wordCharacters;
	}

}
